////////////////////////////////////////////////////
// Name:        variantimage.cpp
// Purpose:     A variant type supporting an image
// Author:      Julian Smart
// Modified by:
// Created:     2006-05-11
// RCS-ID:      $$
// Copyright:   (c) Julian Smart
// Licence:     New BSD License
////////////////////////////////////////////////////

#include "wx/wx.h"

#include "wx/image.h"
#include "wx/dataobj.h"
#include "wx/wfstream.h"
#include "wx/mstream.h"
#include "wx/module.h"

#include "variantutils/varianthandlers.h"
#include "variantutils/variantimage.h"

/*
 * wxPictureVariantData stores the actual data and is ref-counted;
 */

IMPLEMENT_DYNAMIC_CLASS(wxPictureVariantData, wxClonableVariantData)

// Ensure image has been created from the data
bool wxPictureVariantData::MakeImage(bool force)
{
    if (m_image.Ok() && !force)
        return true;

    return m_imageBlock.Load(m_image);
}

wxPictureVariantData::wxPictureVariantData(const wxPictureVariantData& data)
{
    wxASSERT_MSG( (data.GetType() == wxT("image")), wxT("wxPictureVariantData::Copy: Can't copy from this type of data") );

    if (data.GetType() != wxT("image"))
        return;    

    m_image = data.m_image;
    m_imageBlock = data.m_imageBlock;
}

bool wxPictureVariantData::Eq(wxVariantData& data) const
{
    wxASSERT_MSG( (data.GetType() == wxT("image")), wxT("wxPictureVariantData::Eq: argument mismatch") );

    if (data.GetType() != wxT("image"))
        return false;

    wxPictureVariantData& imageData = (wxPictureVariantData&) data;

    // TODO: Not sure how to compare images
    return imageData.m_imageBlock.GetDataSize() == m_imageBlock.GetDataSize();
}

bool wxPictureVariantData::Write(wxString& WXUNUSED(str)) const
{
    return false;
}

bool wxPictureVariantData::Read(wxString& WXUNUSED(str))
{
    wxFAIL_MSG(wxT("Unimplemented"));
    // TODO
    return false;
}

// Set image
void wxPictureVariantData::SetImage(const wxImage& image, int imageType)
{
    m_image = image;
    m_imageBlock.MakeImageBlock(m_image, imageType);
}

#if 0

/*
 * wxPictureVariantData
 */

IMPLEMENT_DYNAMIC_CLASS(wxPictureVariantData, wxRefCountingVariantData)

// Get image block
wxImageBlock& wxPictureVariantData::GetImageBlock()
{
    if (!GetVariantRefData())
        AllocExclusive();

    return GetImageRefData()->GetImageBlock();
}

const wxImageBlock& wxPictureVariantData::GetImageBlock() const
{
    if (!GetVariantRefData())
        ((wxPictureVariantData*)this)->AllocExclusive();

    return GetImageRefData()->GetImageBlock();
}

// Set image
void wxPictureVariantData::SetImage(const wxImage& image, int imageType)
{
    if (!GetVariantRefData())
        AllocExclusive();

    GetImageRefData()->SetImage(image, imageType);
}

// Get image
const wxImage& wxPictureVariantData::GetImage() const
{
    if (!GetVariantRefData())
        ((wxPictureVariantData*)this)->AllocExclusive();

    return GetImageRefData()->GetImage();
}

wxImage& wxPictureVariantData::GetImage()
{
    if (!GetVariantRefData())
        AllocExclusive();

    return GetImageRefData()->GetImage();
}

// Ensure image has been created from the data
bool wxPictureVariantData::MakeImage(bool force)
{
    if (!GetVariantRefData())
        AllocExclusive();

    return GetImageRefData()->MakeImage(force);
}

#endif

// Is this variant an image?
bool wxIsImageVariant(const wxVariant& variant)
{
    return (variant.GetType() == wxT("image"));
}

// Get the image data
wxPictureVariantData* wxGetImageVariantData(const wxVariant& variant)
{
    if (!variant.GetData())
        return NULL;

    wxString type(variant.GetType());

    wxASSERT( (type == wxT("image")));

    if (variant.GetType() == wxT("image"))
        return wxDynamicCast(variant.GetData(), wxPictureVariantData);
    else
        return NULL;
}

// Create image
wxVariant wxCreateImageVariant(const wxString& name)
{
    return wxVariant(new wxPictureVariantData, name);
}

wxVariant wxCreateImageVariant(const wxImage& image, const wxString& name)
{
    wxPictureVariantData* imageData = new wxPictureVariantData;
    imageData->SetImage(image);

    return wxVariant(imageData, name);
}

wxVariant wxCreateImageVariant(const wxImageBlock& imageBlock, const wxString& name)
{
    wxPictureVariantData* imageData = new wxPictureVariantData;
    imageData->SetImageBlock(imageBlock);

    return wxVariant(imageData, name);
}

/*
 * wxPictureVariantHandler knows how to create, load and save an image variant.
 */

class wxPictureVariantHandler: public wxVariantHandler
{
    DECLARE_DYNAMIC_CLASS(wxPictureVariantHandler)
public:
    wxPictureVariantHandler(const wxString& name = wxEmptyString)
        : wxVariantHandler(name)
        { }

    virtual bool ReadValue(const wxString& type, wxVariant& variant, wxInputStream& stream, wxDataInputStream& dataStream);
    virtual bool WriteValue(const wxVariant& variant, wxOutputStream& stream, wxDataOutputStream& dataStream);

    virtual bool CanHandle(const wxString& type);

    // Supply a default value for this type
    virtual wxVariant GetDefaultValue(const wxString& WXUNUSED(type)) { return wxCreateImageVariant(); }
};

IMPLEMENT_DYNAMIC_CLASS(wxPictureVariantHandler, wxVariantHandler)

// Read the variant data from a stream
bool wxPictureVariantHandler::ReadValue(const wxString& type, wxVariant& variant, wxInputStream& stream, wxDataInputStream& dataStream)
{
    if (type == wxT("image"))
    {
        if (variant.IsNull())
        {
            variant.SetData(new wxPictureVariantData);
        }
        wxPictureVariantData* imageData = wxGetImageVariantData(variant);

        wxASSERT(imageData != NULL);

        if (imageData)
        {
            imageData->GetImageBlock().Read(stream, dataStream);
        }

        return true;
    }
    else
        return false;
}

// Write the variant data to the stream
bool wxPictureVariantHandler::WriteValue(const wxVariant& variant, wxOutputStream& stream, wxDataOutputStream& dataStream)
{
    wxString name(variant.GetName());
    // wxASSERT( !name.IsEmpty() );

    wxString type(variant.GetType());
    wxASSERT( !type.IsEmpty() );

    if (type == wxT("image"))
    {
        wxPictureVariantData* imageData = wxGetImageVariantData(variant);

        wxASSERT(imageData != NULL);

        if (imageData)
        {
            imageData->GetImageBlock().Write(stream, dataStream);
        }

        return true;
    }
    else
        return false;
}

bool wxPictureVariantHandler::CanHandle(const wxString& type)
{
    return type == wxT("image");
}

// A module to register wxPictureVariantHandler

class wxPictureVariantHandlerModule: public wxModule
{
DECLARE_DYNAMIC_CLASS(wxPictureVariantHandlerModule)
public:
    wxPictureVariantHandlerModule() {}
    bool OnInit() { wxVariantHandlers::AddHandler(new wxPictureVariantHandler()); return true; };
    void OnExit() {}
};

IMPLEMENT_DYNAMIC_CLASS(wxPictureVariantHandlerModule, wxModule)

